package com.jj.core.client.sim;

import com.alibaba.fastjson.JSON;
import com.jj.config.Constants;
import com.jj.core.encrypt.Enigma;
import com.jj.core.utils.BinUtils;
import com.jj.message.ProtoFormat;
import com.jj.message.battle.UserMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;

/**
 * Copyrights: QidianGroup@JJ
 *
 * @author: LuHan
 * @date: 2018/1/15, 14:53
 */
public class ClientSim {
    private static Logger logger = LoggerFactory.getLogger(ClientSim.class);


    private Socket client = null;
    private String host = null;
    private int port = 0;

    private Enigma encryptor = new Enigma(0);
    private Enigma decryptor = new Enigma(0);

    public ClientSim(String host, int port){
        this.host = host;
        this.port = port;
    }

    public boolean connect(){
        try {
            client = new Socket(host, port);
            return true;
        } catch (IOException e) {
            logger.error("exception", e);
            return false;
        }
    }


    public boolean send(UserMessage ioMessage){
        byte[] data = buildRaw(ioMessage);
        boolean retCode = false;
        OutputStream outputStream = null;
        try {
            outputStream = client.getOutputStream();
            outputStream.write(data);
            outputStream.flush();
            retCode = true;
            logger.debug("send {}", ioMessage.getMsgID());
        } catch (IOException e) {
            logger.error("exception", e);
            retCode = false;
        }
        return retCode;
    }


    public boolean send(Integer msgIdx, String jsonMsg){
        return send(msgIdx.shortValue(),jsonMsg);
    }

    public boolean send(short msgIdx, String jsonMsg){
        boolean retCode = false;
        OutputStream outputStream = null;
        try {
            outputStream = client.getOutputStream();
            byte[] data = buildJSON(msgIdx, jsonMsg);
            outputStream.write(data);
            outputStream.flush();
            retCode = true;
            logger.debug("send {}", msgIdx);
        } catch (IOException e) {
            logger.error("exception", e);
            retCode = false;
        }
        return retCode;
    }


    public boolean send(int msgIdx){
        boolean retCode = false;
        OutputStream outputStream = null;
        try {
            outputStream = client.getOutputStream();
            byte[] data = buildJSON((short) msgIdx, null);
            outputStream.write(data);
            outputStream.flush();
            retCode = true;
            logger.debug("send {}", msgIdx);
        } catch (IOException e) {
            logger.error("exception", e);
            retCode = false;
        }
        return retCode;
    }


    public UserMessage read(){
        UserMessage ioMsg = null;
        try {
            InputStream inputStream = client.getInputStream();
            byte[] lenData = new byte[4];
            int len = inputStream.read(lenData);
            if (len != 4) {
                return ioMsg;
            }
            byte[] msgData = new byte[BinUtils.toInt(lenData, 0) - 4];
            inputStream.read(msgData);
            ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer();
            buf.writeBytes(msgData);
            ioMsg = UserMessage.parseFrom(buf);
//            if(ioMsg.getPayload() != null){
//                decryptor.decrypt(ioMsg.getPayload());
//            }
        }catch(Throwable t){
            logger.error("exception", t);
        }
        return ioMsg;
    }


    private byte[] buildJSON(short msgIdx, String jsonStr){
        UserMessage ioMessage = new UserMessage();
        ioMessage.setJsonMsg(jsonStr);
        ioMessage.setMsgID(msgIdx);
        ioMessage.setProtocolFormat(ProtoFormat.JSON);
        ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer();
        int pbSize = 0;
        byte[] raw = null;
        if(jsonStr != null){
            try {
                raw = jsonStr.getBytes(Constants.ENCODING);
            } catch (UnsupportedEncodingException e) {
                logger.error("exception", e);
                return null;
            }
            pbSize = raw.length;
        }
        buf.writeInt(pbSize+4+2+1);
        buf.writeShort(ioMessage.getMsgID());
        buf.writeByte(ioMessage.getProtocolFormat().getValue());
        if(raw != null)
        {
            //encryptor.encrypt(raw);
            buf.writeBytes(raw);
        }
        byte[] rawBigMsg = new byte[buf.readableBytes()];
        buf.readBytes(rawBigMsg);
        return rawBigMsg;
    }



    private byte[] buildRaw(UserMessage userMessage){
        ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer();
        int pbSize = 0;
        if(userMessage.getPayload() != null){
            pbSize = userMessage.getPayload().length;
        }
        if(userMessage.getRequestId() == null)
        {
            buf.writeInt(pbSize+4+2+1);
        }else{
            buf.writeInt(4+pbSize+4+2+1);
        }

        buf.writeShort(userMessage.getMsgID());
        buf.writeByte(userMessage.getProtocolFormat().getValue());
        if(userMessage.getRequestId() != null){
            buf.writeInt(userMessage.getRequestId());
        }
        if(userMessage.getPayload() != null){
            buf.writeBytes(userMessage.getPayload());
        }
        byte[] raw = new byte[buf.readableBytes()];
        buf.readBytes(raw);
        //decryptor.decrypt(raw);
        return raw;
    }
}
